#ifndef __TESTSCHWARZ_H
#define __TESTSCHWARZ_H 1

#include <life/options.hpp>
#include <life/lifecore/application.hpp>

// (non)linear algebra backend
#include <life/lifealg/backend.hpp>
// function space
#include <life/lifediscr/functionspace.hpp>
// quadrature rules
#include <life/lifepoly/im.hpp>
// import gmsh
#include <life/lifefilters/gmsh.hpp>
// exporter
#include <life/lifefilters/exporter.hpp>
#include <life/lifefilters/gmshtensorizeddomain.hpp>

#include <life/lifepoly/polynomialset.hpp>
// linear operators
//#include <life/lifediscr/operatorlinear.hpp>
#include <life/lifemesh/elements.hpp>
//Variational Formulation
#include <life/lifevf/vf.hpp>
//schéma en temps
#include <life/lifediscr/bdf2.hpp>
//ALE
//#include <life/lifediscr/ale.hpp>
//déplacement du maillage
//#include <life/lifemesh/meshmover.hpp>
//interpolation
#include <life/lifediscr/interpolate.hpp>


namespace Life
{

template<int Dim,
         int Order,
         template<uint16_type,uint16_type,uint16_type> class Entity>
class Test_Schwarz
    :
        public Application
{
    typedef Application super;
public:


    typedef double value_type;

    typedef Backend<value_type> backend_type;
    typedef boost::shared_ptr<backend_type> backend_ptrtype;

    //matrix
    typedef typename backend_type::sparse_matrix_ptrtype sparse_matrix_ptrtype;
    typedef typename backend_type::vector_ptrtype vector_ptrtype;

    //----------------------------------------------------------------------------------------------------------//

    //mesh
    typedef Entity<Dim,1,Dim> convex_type;
    typedef Mesh<convex_type> mesh_type;
    typedef boost::shared_ptr<mesh_type> mesh_ptrtype;

    //basis
    typedef bases< Lagrange<Order, Scalar> > basis_type;
    typedef bases< Lagrange<Order, Vectorial> > basis_type2;

    //function space
    typedef FunctionSpace<mesh_type, basis_type> space_type;
    typedef boost::shared_ptr<space_type> space_ptrtype;

    BOOST_MPL_ASSERT( ( boost::is_same<typename space_type::bases_list, basis_type> ) );
    
    typedef FunctionSpace<mesh_type, basis_type2> space_type2;
    typedef boost::shared_ptr<space_type2> space_ptrtype2;

    BOOST_MPL_ASSERT( ( boost::is_same<typename space_type2::bases_list, basis_type2> ) );
//    BOOST_MPL_ASSERT( ( boost::is_same<typename mpl::at<typename space_type2::bases_list,mpl::int_<0> >::type, basis_type> ) );

    //functions 
    typedef typename space_type::element_type element_type;
    typedef typename space_type2::element_type element_type2;    


    //----------------------------------------------------------------------------------------------------------//

    // export
    typedef Exporter<mesh_type> export_type;
    typedef boost::shared_ptr<export_type> export_ptrtype;


    Test_Schwarz( int argc, char** argv, AboutData const& ad, po::options_description const& od )
        :
        super( argc, argv, ad, od ),
        M_backend( backend_type::build( this->vm() ) ),
        meshSize( this->vm()["hsize"].template as<double>() ),
        exporter( Exporter<mesh_type>::New( this->vm(), this->about().appName() ) ),
        exporter1( Exporter<mesh_type>::New( this->vm(), "maillage1" ) ),
        exporter2( Exporter<mesh_type>::New( this->vm(), "maillage2" ) )
    {
        //Masse volumique
/*        rho = this->vm()["rho"].template as<double>();
        mu = this->vm()["mu"].template as<value_type>();
        penalbc = this->vm()["bccoeff"].template as<value_type>();
        Vitesse_Entree = this->vm()["entree-v"].template as<value_type>();
        Pression_Sortie = this->vm()["sortie-p"].template as<value_type>();*/
    }


    /**
     * create the mesh using mesh size \c meshSize
     */
    mesh_ptrtype createMesh( double meshSize );
  mesh_ptrtype createSubMesh( mesh_ptrtype/*&*/ mesh, int marker );
  
    mesh_ptrtype createMesh1( double meshSize );
    mesh_ptrtype createMesh2( double meshSize );

    /**
     * run the convergence test
     */
    void run();

    void updateJacobian( const vector_ptrtype& X, sparse_matrix_ptrtype& J);
    void updateResidual( const vector_ptrtype& X, vector_ptrtype& R );

private:

    void test_data_maillage();
    void test_interpolation();
    void test_composantes_champs();
    
    void problem(element_type& u , element_type& v, sparse_matrix_ptrtype& A , vector_ptrtype& B );
    void problem1(element_type& u , element_type& v, element_type& u_autre );
    void problem2(element_type& u , element_type& v, element_type& u_autre );
    /**
     * solve system
     */
    void solve( sparse_matrix_ptrtype const& D, element_type& u, vector_ptrtype const& F, bool is_sym );

    /**
     * export results to ensight format (enabled by  --export cmd line options)
     */
    void exportResults( element_type& u, element_type& u1, element_type& u2, double time=0 );

private:

    backend_ptrtype M_backend;
/*
    space_ptrtype Xh;
    space_ptrtype Xh1;
    space_ptrtype Xh2;*/



    double meshSize;

 /*   double rho;
    double mu;
    double penalbc;
    double Vitesse_Entree;
    double Pression_Sortie;*/

    export_ptrtype exporter;
    export_ptrtype exporter1;
    export_ptrtype exporter2;

}; // Test_Schwarz
} // Life
#endif /* __TESTSCHWARZ_H */
